package com.fingard.dsp.bank.directbank.baofoo01;

import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.dsp.bank.directbank.baofoo01.util.FormatUtil;
import com.fingard.dsp.bank.directbank.baofoo01.util.HttpUtil;
import com.fingard.dsp.bank.directbank.baofoo01.util.SecurityUtil;
import com.fingard.dsp.bank.directbank.baofoo01.util.SignatureUtils;
import com.fingard.net.WebRequest;
import com.fingard.text.StringHelper;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;

public class BaoFoo01Base extends DirectBase {
    protected String getCharset() {
        return getBankConfig().getCharset("UTF-8");
    }

    protected String sendToBank(String pFor, Map<String, String> postParams) {
        String serverUrl = bankFront.getUrl(pFor);
        WriteBankLogLn2("发送银行服务地址:" + serverUrl);

        if (postParams.isEmpty()) {
            return "参数不能为空！";
        }
        String PostParms = "";
        int PostItemTotal = postParams.keySet().size();
        int Itemp = 0;
        for (String key : postParams.keySet()) {
            PostParms += key + "=" + postParams.get(key);
            Itemp++;
            if (Itemp < PostItemTotal) {
                PostParms += "&";
            }
        }
        WriteBankLogStep2(PostParms);
        String tmpStrRet = HttpUtil.requestForm(serverUrl, PostParms);
        WriteBankLogLn2("银行返回密文数据:\r\n" + tmpStrRet);
        return tmpStrRet;
    }


    protected String[] sendToBank(String p_for, Map<String, String> p_reqMap, ActSetItem actItem) throws Exception {
        String[] retStr = new String[]{"", ""};

        WriteBankLogLn2("提交宝付服务器地址：" + bankFront.getUrl(p_for));

        String p_reqStr = "";
        for (Map.Entry<String, String> m : p_reqMap.entrySet()) {
            if (!p_reqStr.equals("")) {
                p_reqStr += "&";
            }

            p_reqStr += m.getKey() + "=" + m.getValue();
        }

        WriteBankLogStep2(p_reqStr);

        WebRequest tmpWebRequest = new WebRequest(bankFront.getUrl(p_for));
        tmpWebRequest.setConnectTimeout(60000);

        byte[] tmpUpBytes = p_reqStr.getBytes(getCharset());
        retStr = tmpWebRequest.upload(tmpUpBytes, getCharset());
        WriteBankLogStep3(retStr[0] + retStr[1]);
        return retStr;
    }

    protected String getQryTransID() {
        Date tmpDateNow = new Date();
        return Format.DateTime17SSSFormat.format(tmpDateNow);
    }

    /*
     * Base64加密
     */
    public String sign(Map<String, String> DateArry, ActSetItem actItem) throws Exception {
        String SignVStr = FormatUtil.coverMap2String(DateArry);
        WriteBankLogLn("SHA-1摘要字串：" + SignVStr);
        String signature = SecurityUtil.sha1X16(SignVStr, "UTF-8");//签名
        WriteBankLogLn("SHA-1摘要结果：" + signature);
        String sign = SignatureUtils.encryptByRSA(signature, actItem.ownKeyStorePath, actItem.ownKeyPassword);
        WriteBankLogLn("RSA签名结果：" + sign);
        return sign;
    }

    /*
     * Base64加密
     */
    public String Base64Encode(String str) throws UnsupportedEncodingException {
        byte[] bytes = new Base64().encode(str.getBytes(getCharset()));

        return new String(bytes, getCharset());
    }

    /*
     * Base64解密
     */
    public String Base64Decode(String str) throws UnsupportedEncodingException, IOException {
        byte[] bytes = new Base64().decode(str.getBytes(getCharset()));

        return new String(bytes, getCharset());
    }

    /**
     * RSA私钥加密
     */
    public String encryptByPriPfxFile(String src, String pfxPath, String priKeyPass) throws Exception {
        KeyStore ks = KeyStore.getInstance("PKCS12");
        FileInputStream fis = new FileInputStream(pfxPath);

        char[] keyPassword = null;
        if (StringHelper.hasAnyChar(priKeyPass)) {
            keyPassword = priKeyPass.toCharArray();
        }
        ks.load(fis, keyPassword);
        fis.close();
        fis = null;

        @SuppressWarnings("rawtypes")
        Enumeration enumAlias = ks.aliases();

        String keyAlias = null;
        if (enumAlias.hasMoreElements()) {
            keyAlias = (String) enumAlias.nextElement();
        }

        PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, keyPassword);

        if (privateKey == null) {
            return null;
        }

        byte[] destBytes = rsaByPrivateKey(src.getBytes(), privateKey, Cipher.ENCRYPT_MODE);

        if (destBytes == null) {
            return null;
        }
        return byte2Hex(destBytes);
    }

    /**
     * 将byte[] 转换成字符串
     */
    public String byte2Hex(byte[] srcBytes) {
        StringBuilder hexRetSB = new StringBuilder();
        for (byte b : srcBytes) {
            String hexString = Integer.toHexString(0x00ff & b);
            hexRetSB.append(hexString.length() == 1 ? 0 : "").append(hexString);
        }
        return hexRetSB.toString();
    }

    /**
     * 将16进制字符串转为转换成字符串
     */
    public byte[] hex2Bytes(String source) {
        byte[] sourceBytes = new byte[source.length() / 2];
        for (int i = 0; i < sourceBytes.length; i++) {
            sourceBytes[i] = (byte) Integer.parseInt(source.substring(i * 2, i * 2 + 2), 16);
        }
        return sourceBytes;
    }

    /**
     * 加密
     */
    public byte[] rsaByPrivateKey(byte[] srcData, PrivateKey privateKey, int mode) {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(mode, privateKey);
            // 分段加密
            int blockSize = (mode == Cipher.ENCRYPT_MODE) ? 117 : 128;
            byte[] decryptData = null;
            for (int i = 0; i < srcData.length; i += blockSize) {
                byte[] doFinal = cipher.doFinal(subarray(srcData, i, i + blockSize));
                decryptData = addAll(decryptData, doFinal);
            }
            return decryptData;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public byte[] subarray(byte[] array, int startIndexInclusive, int endIndexExclusive) {
        if (array == null) {
            return null;
        }
        if (startIndexInclusive < 0) {
            startIndexInclusive = 0;
        }
        if (endIndexExclusive > array.length) {
            endIndexExclusive = array.length;
        }
        int newSize = endIndexExclusive - startIndexInclusive;
        if (newSize <= 0) {
            return new byte[0];
        }

        byte[] subarray = new byte[newSize];
        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
        return subarray;
    }

    public byte[] addAll(byte[] array1, byte[] array2) {
        if (array1 == null) {
            return clone(array2);
        } else if (array2 == null) {
            return clone(array1);
        }
        byte[] joinedArray = new byte[array1.length + array2.length];
        System.arraycopy(array1, 0, joinedArray, 0, array1.length);
        System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
        return joinedArray;
    }

    public byte[] clone(byte[] array) {
        if (array == null) {
            return null;
        }
        return (byte[]) array.clone();
    }

    /**
     * RSA公钥解密
     *
     * @throws Exception
     */
    public String decryptByPubCerFile(String src, String pubCerPath) throws Exception {
        X509Certificate cert = null;
        FileInputStream fis = null;
        try {

            fis = new FileInputStream(pubCerPath);
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            cert = (X509Certificate) cf.generateCertificate(fis);
            fis.close();

            PublicKey publicKey = cert.getPublicKey();
            if (publicKey == null) {
                return null;
            }
            byte[] destBytes = rsaByPublicKey(hex2Bytes(src), publicKey, Cipher.DECRYPT_MODE);

            if (destBytes == null) {
                return null;
            }
            return new String(destBytes, getCharset());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }

    /**
     * 公钥解密算法
     */
    public byte[] rsaByPublicKey(byte[] srcData, PublicKey publicKey, int mode) throws Exception {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(mode, publicKey);
            // 分段加密
            int blockSize = (mode == Cipher.ENCRYPT_MODE) ? 117 : 128;
            byte[] encryptedData = null;
            for (int i = 0; i < srcData.length; i += blockSize) {
                // 注意要使用2的倍数，否则会出现加密后的内容再解密时为乱码
                byte[] doFinal = cipher.doFinal(subarray(srcData, i, i + blockSize));
                encryptedData = addAll(encryptedData, doFinal);
            }
            return encryptedData;

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
}
